using Mono.Cecil;
using Mono.Cecil.Cil;

namespace Cil.Ast;

public sealed class ArrayGetItemExpression : SingleInstructionExpression
{
	public const int ArrayPos = 0;
	public const int IndexPos = 1;
	public const int MaxNodes = 2;

	public ArrayGetItemExpression(Context context, Instruction position, Expression exp_array, Expression exp_index) : base(context, position)
	{
		if(!(exp_array.ReturnType is ArrayType))
		{
			throw new ArgumentException($"exp_array is not array ({exp_array.ReturnType})");
		}

		var arrayItemType = (exp_array.ReturnType as ArrayType)?.ElementType;

		if(exp_index.ReturnType.MetadataType != MetadataType.Int32)
		{
			throw new ArgumentException(string.Format("exp_index should be Int32 ({0})", exp_index.ReturnType));
		}

		// base class
		ReturnType = arrayItemType;
		ReadsStack = 2;
		WritesStack = 1;
		Nodes = new FixedList<Expression>(MaxNodes);

		// this
		ItemType = arrayItemType;
		ArrayExpression = exp_array;
		IndexExpression = exp_index;
	}

	public TypeReference ItemType { get; private set; }

	public Expression ArrayExpression { get { return Nodes[ArrayPos]; } set { Nodes[ArrayPos] = value; value.ParentNode = this; } }

	public Expression IndexExpression { get { return Nodes[IndexPos]; } set { Nodes[IndexPos] = value; value.ParentNode = this; } }

	public override string ToString()
	{
		return string.Format("{0}[{1}]", ArrayExpression, IndexExpression);
	}
}

public static partial class IlAst
{
	public static ArrayGetItemExpression ArrayGetItem(Context context, Instruction position, Expression exp_array, Expression exp_index)
	{
		return new ArrayGetItemExpression(context, position, exp_array, exp_index);
	}
}